// // ======================================================================== // Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 // and Apache License v2.0 which accompanies this distribution. // // The Eclipse Public License is available at // http://www.eclipse.org/legal/epl-v10.html // // The Apache License v2.0 is available at // http://www.opensource.org/licenses/apache2.0.php // // You may elect to redistribute this code under either of these licenses. // ======================================================================== // package org.eclipse.jetty.jaas.spi; import java.io.IOException; import java.security.Principal; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.security.auth.Subject; import javax.security.auth.callback.Callback; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.callback.NameCallback; import javax.security.auth.callback.PasswordCallback; import javax.security.auth.callback.UnsupportedCallbackException; import javax.security.auth.login.FailedLoginException; import javax.security.auth.login.LoginException; import javax.security.auth.spi.LoginModule; import org.eclipse.jetty.jaas.JAASPrincipal; import org.eclipse.jetty.jaas.JAASRole; import org.eclipse.jetty.jaas.callback.ObjectCallback; /** * AbstractLoginModule * * Abstract base class for all LoginModules. Subclasses should * just need to implement getUserInfo method. */ public abstract class AbstractLoginModule implements LoginModule { private CallbackHandler callbackHandler; private boolean authState = false; private boolean commitState = false; private JAASUserInfo currentUser; private Subject subject; /** * JAASUserInfo * * This class unites the UserInfo data with jaas concepts * such as Subject and Principals */ public class JAASUserInfo { private UserInfo user; private Principal principal; private List<JAASRole> roles; public JAASUserInfo (UserInfo u) { this.user = u; this.principal = new JAASPrincipal(u.getUserName()); } public String getUserName () { return this.user.getUserName(); } public Principal getPrincipal() { return this.principal; } public void setJAASInfo (Subject subject) { subject.getPrincipals().add(this.principal); subject.getPrivateCredentials().add(this.user.getCredential()); subject.getPrincipals().addAll(roles); } public void unsetJAASInfo (Subject subject) { subject.getPrincipals().remove(this.principal); subject.getPrivateCredentials().remove(this.user.getCredential()); subject.getPrincipals().removeAll(this.roles); } public boolean checkCredential (Object suppliedCredential) { return this.user.checkCredential(suppliedCredential); } public void fetchRoles() throws Exception { this.user.fetchRoles(); this.roles = new ArrayList<JAASRole>(); if (this.user.getRoleNames() != null) { Iterator<String> itor = this.user.getRoleNames().iterator(); while (itor.hasNext()) this.roles.add(new JAASRole((String)itor.next())); } } } public Subject getSubject () { return this.subject; } public void setSubject (Subject s) { this.subject = s; } public JAASUserInfo getCurrentUser() { return this.currentUser; } public void setCurrentUser (JAASUserInfo u) { this.currentUser = u; } public CallbackHandler getCallbackHandler() { return this.callbackHandler; } public void setCallbackHandler(CallbackHandler h) { this.callbackHandler = h; } public boolean isAuthenticated() { return this.authState; } public boolean isCommitted () { return this.commitState; } public void setAuthenticated (boolean authState) { this.authState = authState; } public void setCommitted (boolean commitState) { this.commitState = commitState; } /** * @see javax.security.auth.spi.LoginModule#abort() * @throws LoginException if unable to abort */ public boolean abort() throws LoginException { this.currentUser = null; return (isAuthenticated() && isCommitted()); } /** * @see javax.security.auth.spi.LoginModule#commit() * @return true if committed, false if not (likely not authenticated) * @throws LoginException if unable to commit */ public boolean commit() throws LoginException { if (!isAuthenticated()) { currentUser = null; setCommitted(false); return false; } setCommitted(true); currentUser.setJAASInfo(subject); return true; } public Callback[] configureCallbacks () { Callback[] callbacks = new Callback[3]; callbacks[0] = new NameCallback("Enter user name"); callbacks[1] = new ObjectCallback(); callbacks[2] = new PasswordCallback("Enter password", false); //only used if framework does not support the ObjectCallback return callbacks; } public boolean isIgnored () { return false; } public abstract UserInfo getUserInfo (String username) throws Exception; /** * @see javax.security.auth.spi.LoginModule#login() * @return true if is authenticated, false otherwise * @throws LoginException if unable to login */ public boolean login() throws LoginException { try { if (isIgnored()) return false; if (callbackHandler == null) throw new LoginException ("No callback handler"); Callback[] callbacks = configureCallbacks(); callbackHandler.handle(callbacks); String webUserName = ((NameCallback)callbacks[0]).getName(); Object webCredential = null; webCredential = ((ObjectCallback)callbacks[1]).getObject(); //first check if ObjectCallback has the credential if (webCredential == null) webCredential = ((PasswordCallback)callbacks[2]).getPassword(); //use standard PasswordCallback if ((webUserName == null) || (webCredential == null)) { setAuthenticated(false); throw new FailedLoginException(); } UserInfo userInfo = getUserInfo(webUserName); if (userInfo == null) { setAuthenticated(false); throw new FailedLoginException(); } currentUser = new JAASUserInfo(userInfo); setAuthenticated(currentUser.checkCredential(webCredential)); if (isAuthenticated()) { currentUser.fetchRoles(); return true; } else throw new FailedLoginException(); } catch (IOException e) { throw new LoginException (e.toString()); } catch (UnsupportedCallbackException e) { throw new LoginException (e.toString()); } catch (Exception e) { if (e instanceof LoginException) throw (LoginException)e; throw new LoginException (e.toString()); } } /** * @see javax.security.auth.spi.LoginModule#logout() * @return true always * @throws LoginException if unable to logout */ public boolean logout() throws LoginException { this.currentUser.unsetJAASInfo(this.subject); this.currentUser = null; return true; } /** * @see javax.security.auth.spi.LoginModule#initialize(javax.security.auth.Subject, javax.security.auth.callback.CallbackHandler, java.util.Map, java.util.Map) * @param subject the subject * @param callbackHandler the callback handler * @param sharedState the shared state map * @param options the option map */ public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String,?> sharedState, Map<String,?> options) { this.callbackHandler = callbackHandler; this.subject = subject; } }